/**
 * 
 * LuceneDaoImpl.java
 * Defender
 * 2013-11-23
 */
package com.ls.fw.data.search.impl.dao.base.impl;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ls.fw.data.search.impl.dao.base.LuceneDao;
import com.ls.fw.data.search.impl.lucene.bean.SearchResult;
import com.ls.fw.data.search.impl.lucene.exception.IndexException;

/**
 * com.demo.lucene LuceneDaoImpl
 * 
 * @author Defender 2013-11-23 下午08:34:21
 */
public class LuceneDaoImpl implements LuceneDao {

	public static final Version VERSION = Version.LUCENE_4_10_2;
	public static final Analyzer default_analyzer = new StandardAnalyzer();

	protected Logger logger = LoggerFactory.getLogger(this.getClass());
	
	private Directory dir = null;//索引文件目录
	
	private Analyzer analyzer = null;//分析器

	private IndexWriter indexWriter = null;//索引写入器
	
	private IndexReader indexReader = null;//索引读取器
	
	private boolean autoCommit = false;//是否自动提交
	
	private String indexFilePath = "";//索引文件路径
	
	private boolean opened = false;//是否打开索引文件
	
	public LuceneDaoImpl(Directory directory) throws IndexException {
		this.open(directory,default_analyzer);
	}
	
	
	public LuceneDaoImpl(Directory directory,Analyzer analyzer ) throws IndexException {
		this.open(directory,analyzer);
	}
	
	
	public LuceneDaoImpl(String indexFilePath,Analyzer analyzer ) throws IndexException {
		this.open(indexFilePath,analyzer);
	}
	
	
	public LuceneDaoImpl(String indexFilePath) throws IndexException {
		this.open(indexFilePath,default_analyzer);
	}

	
	public void addDoc(Document doc) throws IndexException {
		IndexWriter indexWriter = null;
		try {
			indexWriter = this.getIndexWriter();
			this.addDoc(indexWriter, doc);
			if(this.isAutoCommit()){
				indexWriter.commit();
			}
		} catch (IOException e) {
			if(this.isAutoCommit()){
				try {
					indexWriter.rollback();
				} catch (IOException e1) {
					throw new IndexException(e1.getMessage(),e1.getCause());
				}
			}
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
			
		}
	}

	
	public void addDoc(IndexWriter indexWriter, Document doc)
			throws IndexException {
		try {
			indexWriter.addDocument(doc);
		} catch (IOException e) {
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
			
		}
	}
 
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.demo.lucene.LuceneDao#addDoc(java.util.List,
	 * org.apache.lucene.analysis.Analyzer)
	 */
	@Override
	public void addDoc(IndexWriter indexWriter, List<IndexableField> list) throws IndexException {
		if (list != null) {
			Document doc = new Document();
			for (IndexableField indexableField : list) {
				doc.add(indexableField);
			}
			this.addDoc(indexWriter, doc);
		}

	}

	public void addDoc(List<IndexableField> list) throws IndexException {
		IndexWriter indexWriter = null;
		try {
			indexWriter = this.getIndexWriter();
			this.addDoc(indexWriter, list);
			if(this.isAutoCommit()){
				indexWriter.commit();
			}
		} catch (IOException e) {
			if(this.isAutoCommit()){
				try {
					indexWriter.rollback();
				} catch (IOException e1) {
					throw new IndexException(e1.getMessage(),e1.getCause());
				}
			}
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
			
		}
	}

	public void addDocs(IndexWriter indexWriter, List<Document> docs)
			throws IndexException {
		if (docs != null) {
			try {
				for (Document document : docs) {
					this.addDoc(indexWriter, document);
				}
			} finally {
			}
		}
	}

	public void addDocs(List<Document> docs) throws IndexException {
		IndexWriter indexWriter = null;
		try {
			indexWriter = this.getIndexWriter();
			this.addDocs(indexWriter, docs);
			if(this.isAutoCommit()){
				indexWriter.commit();
			}
		} catch (IOException e) {
			if(this.isAutoCommit()){
				try {
					indexWriter.rollback();
				} catch (IOException e1) {
					throw new IndexException(e1.getMessage(),e1.getCause());
				}
			}
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
			
		}
	}
 

	public void deleteAllDoc() throws IndexException {
		IndexWriter indexWriter = null;
		try {
			indexWriter = this.getIndexWriter();
			this.deleteAllDoc(indexWriter);
			if(this.isAutoCommit()){
				indexWriter.commit();
			}
		} catch (IOException e) {
			if(this.isAutoCommit()){
				try {
					indexWriter.rollback();
				} catch (IOException e1) {
					throw new IndexException(e1.getMessage(),e1.getCause());
				}
			}
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
			
		}
	}


	public void deleteAllDoc(IndexWriter indexWriter) throws IndexException {
		this.deleteAllDoc(indexWriter);
	}



	public void deleteDoc(IndexWriter indexWriter, Query... query)
			throws IndexException {
		try {
			indexWriter.deleteDocuments(query);
		} catch (IOException e) {
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.demo.lucene.base.LuceneDao#deleteDoc(org.apache.lucene.index.Term[])
	 */
	@Override
	public void deleteDoc(IndexWriter indexWriter, Term... term)
			throws IndexException {
		try {
			indexWriter.deleteDocuments(term);
		} catch (IOException e) {
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
		}
	}

	public void deleteDoc(Query... query) throws IndexException {
		IndexWriter indexWriter = null;
		try {
			indexWriter = this.getIndexWriter();
			this.deleteDoc(indexWriter, query);
			if(this.isAutoCommit()){
				indexWriter.commit();
			}
		} catch (IOException e) {
			if(this.isAutoCommit()){
				try {
					indexWriter.rollback();
				} catch (IOException e1) {
					throw new IndexException(e1.getMessage(),e1.getCause());
				}
			}
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
			
		}
	}

	public void deleteDoc(Term... term) throws IndexException {
		IndexWriter indexWriter = null;
		try {
			indexWriter = this.getIndexWriter();
			this.deleteDoc(indexWriter, term);
			if(this.isAutoCommit()){
				indexWriter.commit();
			}
		} catch (IOException e) {
			if(this.isAutoCommit()){
				try {
					indexWriter.rollback();
				} catch (IOException e1) {
					throw new IndexException(e1.getMessage(),e1.getCause());
				}
			}
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
			
		}
	}


	public Directory getDir() {
		return dir;
	}

	public IndexReader getIndexReader(Directory dir) throws IndexException {
		try {
			return DirectoryReader.open(dir);
		} catch (IOException e) {
			throw new IndexException(e.getMessage(),e.getCause());
		}
	}

	public synchronized IndexReader getDefaultIndexReader() throws IndexException {
		try {
			return DirectoryReader.open(dir);
		} catch (IOException e) {
			throw new IndexException(e.getMessage(),e.getCause());
		}
	}
	
	public synchronized IndexWriter getDefaultIndexWriter() throws IndexException {
		return  this.getNewIndexWriter(this.getAnalyzer());
	}

	public IndexWriter getNewIndexWriter(Analyzer analyzer) throws IndexException {
		return this.getNewIndexWriter(analyzer,IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
	}

	public IndexWriter getNewIndexWriter(Analyzer analyzer, OpenMode openMode)
			throws IndexException {
		IndexWriterConfig iwc = new IndexWriterConfig(VERSION, analyzer);
		iwc.setOpenMode(openMode);
		return this.getNewIndexWriter(iwc);
	}

	public IndexWriter getNewIndexWriter(IndexWriterConfig iwc) throws IndexException {
		//this.unLockDir();
		try {
			return new IndexWriter(this.dir, iwc);
		} catch (IOException e) {
			throw new IndexException(e.getMessage(),e.getCause());
		}
	}
	 
	 public TopDocs search(IndexSearcher searcher,Query query,int page,int pageSize)  throws IndexException{
		    TopScoreDocCollector topCollector = TopScoreDocCollector.create(searcher.getIndexReader().maxDoc(), false);//返回所有条数的一个集合
		    try {
				searcher.search(query, topCollector);
			} catch (IOException e) {
				throw new IndexException(e.getMessage(),e.getCause());
			}
			//System.out.println("一共有多少条记录命中:"+topCollector.getTotalHits());
			int start = (page - 1) * pageSize;//start:开始条数   pageSize：显示多少条
			return topCollector.topDocs(start, pageSize);
	 }
				
		   
	public TopDocs search(IndexSearcher searcher,Query query,int pageSize)  throws IndexException{
		try {
			return searcher.search(query, pageSize);
		} catch (IOException e) {
			throw new IndexException(e.getMessage(),e.getCause());
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.demo.lucene.LuceneDao#search(org.apache.lucene.search.Query)
	 */
	@Override
	public SearchResult search(Query query, int pageSize) throws IndexException {
		IndexSearcher searcher = new IndexSearcher(this.getIndexReader());
		TopDocs topdocs = null;
		try {
			topdocs = searcher.search(query, pageSize);
		} catch (IOException e) {
			throw new IndexException(e.getMessage(),e.getCause());
		}
		return new SearchResult(topdocs, searcher);
	}

	public void setDir(Directory dir) {
		this.dir = dir;
	}

	public void updateDoc(IndexWriter indexWriter, Term term, Document doc)
			throws IndexException {
		try {
			// Add new documents to an existing index:
			// indexWriter =
			// this.getIndexWriter(analyzer,OpenMode.CREATE_OR_APPEND);
			indexWriter.updateDocument(term, doc, analyzer);
		} catch (IOException e) {
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
		}
	}
	
	public void updateDoc(Term term, Document doc) throws IndexException {
		IndexWriter indexWriter = null;
		try {
			indexWriter = this.getIndexWriter();
			this.updateDoc(indexWriter, term, doc);
			if(this.isAutoCommit()){
				indexWriter.commit();
			}
		} catch (IOException e) {
			if(this.isAutoCommit()){
				try {
					indexWriter.rollback();
				} catch (IOException e1) {
					throw new IndexException(e1.getMessage(),e1.getCause());
				}
			}
			throw new IndexException(e.getMessage(),e.getCause());
		} finally {
			
		}

	}
	
	
	private void close(IndexWriter indexWriter) {
		if (null != indexWriter) {
			try {
				indexWriter.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			indexWriter = null;
		}
		this.unLockDir();
	}
	
	
	private void close(IndexReader indexReader) {
		if (null != indexReader) {
			try {
				indexReader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			indexReader = null;
		}
	}

	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#close()
	 */
	@Override
	public void close() throws IndexException {
		this.close(indexReader);
		this.close(indexWriter);
		if(this.dir!=null){
			try{
				this.dir.close();
			}catch (Exception e) {
			}
			this.dir = null;
		}
		if(this.analyzer!=null){
			try{
				this.analyzer.close();
			}catch (Exception e) {
			}
			this.analyzer = null;
		}
		this.opened = false;
	}
	private void unLockDir(){ 
		try {
			if (dir != null && IndexWriter.isLocked(dir)) {
				IndexWriter.unlock(dir);// 注意解锁
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 * @return the analyzer
	 */
	public Analyzer getAnalyzer() {
		if(this.analyzer==null){
			return default_analyzer;
		}
		return this.analyzer;
	}
	/**
	 * @param analyzer the analyzer to set
	 */
	public void setAnalyzer(Analyzer analyzer) {
		this.analyzer = analyzer;
	}


	/**
	 * @param indexWriter the indexWriter to set
	 */
	public void setIndexWriter(IndexWriter indexWriter) {
		this.indexWriter = indexWriter;
	}


	/**
	 * @param indexReader the indexReader to set
	 */
	public void setIndexReader(IndexReader indexReader) {
		this.indexReader = indexReader;
	}
	

	public IndexReader getIndexReader() throws IndexException {
		if(this.indexReader==null){
			this.indexReader = getDefaultIndexReader();
		}
		return this.indexReader;
	}


	/**
	 * @return the autoCommit
	 */
	@Override
	public boolean isAutoCommit() {
		return this.autoCommit;
	}


	/**
	 * @param autoCommit the autoCommit to set
	 */
	public void setAutoCommit(boolean autoCommit) {
		this.autoCommit = autoCommit;
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#commit()
	 */
	@Override
	public void commit() throws IndexException {
		this.indexWriter = this.getIndexWriter();
		if(this.indexWriter!=null){
			try {
				this.indexWriter.commit();
			} catch (IOException e) {
				throw new IndexException(e.getMessage(),e.getCause());
			}
		}
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#rollback()
	 */
	@Override
	public void rollback() throws IndexException {
		this.indexWriter = this.getIndexWriter();
		if(this.indexWriter!=null){
			try {
				this.indexWriter.rollback();
			} catch (IOException e) {
				throw new IndexException(e.getMessage(),e.getCause());
			}
		}
	}

	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#open()
	 */
	@Override
	public void open() throws IndexException {
		this.open(this.indexFilePath,this.getAnalyzer());
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#open(org.apache.lucene.store.Directory)
	 */
	@Override
	public void open(Directory directory) throws IndexException {
		this.open(directory, this.getAnalyzer());
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#open(org.apache.lucene.store.Directory, org.apache.lucene.analysis.Analyzer)
	 */
	@Override
	public void open(Directory directory, Analyzer analyzer) throws IndexException {
		this.dir = directory;
		this.analyzer = analyzer;
		this.opened = true;
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#open(java.lang.String, org.apache.lucene.analysis.Analyzer)
	 */
	@Override
	public void open(String indexFilePath, Analyzer analyzer)
			throws IndexException {
		final File docDir = new File(indexFilePath);
		if (!docDir.exists()) {
			docDir.mkdirs();
		}
		if(!opened){
			this.indexFilePath = indexFilePath;
			try {
				this.open(FSDirectory.open(new File(indexFilePath)), analyzer);
			} catch (IOException e) {
				throw new IndexException(e.getMessage(),e.getCause());
			}
		}
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#open(java.lang.String)
	 */
	@Override
	public void open(String indexFilePath) throws IndexException {
		this.open(indexFilePath, this.getAnalyzer());
	}
	
	public boolean isOpen(){
		return opened;
	}

	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#getIndexWriter()
	 */
	@Override
	public synchronized IndexWriter getIndexWriter() throws IndexException {
		if(this.indexWriter==null){
			this.indexWriter = this.getDefaultIndexWriter();
		}
		return this.indexWriter;
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#reOpen()
	 */
	@Override
	public synchronized void reOpen() throws IndexException {
		 this.close();
		 this.open();
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#reOpen(org.apache.lucene.store.Directory)
	 */
	@Override
	public void reOpen(Directory directory) throws IndexException {
		 this.close();
		 this.open(directory);
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#reOpen(org.apache.lucene.store.Directory, org.apache.lucene.analysis.Analyzer)
	 */
	@Override
	public void reOpen(Directory directory, Analyzer analyzer)
			throws IndexException {
		 this.close();
		 this.open(directory,analyzer);
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#reOpen(java.lang.String, org.apache.lucene.analysis.Analyzer)
	 */
	@Override
	public void reOpen(String indexFilePath, Analyzer analyzer)
			throws IndexException {
		 this.close();
		 this.open(indexFilePath,analyzer);
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#reOpen(java.lang.String)
	 */
	@Override
	public void reOpen(String indexFilePath) throws IndexException {
		 this.close();
		 this.open(indexFilePath);
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#reOpenIndexReader()
	 */
	@Override
	public void reOpenIndexReader() throws IndexException {
		this.closeIndexReader();
		this.indexReader = this.getIndexReader();
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#closeIndexWriter()
	 */
	@Override
	public void closeIndexWriter() throws IndexException {
		if (null != indexWriter) {
			try {
				indexWriter.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			indexWriter = null;
		}
	}


	/* (non-Javadoc)
	 * @see com.demo.lucene.base.LuceneDao#closeIndexReader()
	 */
	@Override
	public void closeIndexReader() throws IndexException {
		if (null != indexReader) {
			try {
				indexReader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			indexReader = null;
		}
	}

}
